package com.sparrow.common.log;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
import ch.qos.logback.core.util.FileSize;
import com.sparrow.common.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 自定义logback工厂
 */
public class LogbackLoggerFactory {

    private static LoggerContext loggerContext;
    static {
        loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    }

    /**
     * 注册系统日志类，
     * 设置日志类的静态字段,每个字段都应该是个Class类型
     * @param clazz
     * @param <T>
     */
    public static <T> void reg(Class<T> clazz) {
        if (!SystemLogger.class.isAssignableFrom(clazz)) {
            throw new RuntimeException("需要继承SystemLogger");
        }
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
                continue;
            }
            if (!clazz.isAssignableFrom(f.getType())) {
                continue;
            }
            try {
                Logger logger = LogbackLoggerFactory.getLogger(f.getName());
                T holderInstance = (T) clazz.getConstructors()[0].newInstance();
                SystemLogger systemLogger = (SystemLogger) holderInstance;
                systemLogger.setLogger(logger);
                //静态字段设置 holder
                f.set(null, holderInstance);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static Logger getLogger(String name) {
        ch.qos.logback.classic.Logger logger = loggerContext.exists(name);
        if (logger != null) {
            return logger;
        }
        logger = loggerContext.getLogger(name);
        Appender<ILoggingEvent> appender = createAppender(logger);
        logger.addAppender(appender);
        logger.setLevel(Level.valueOf("debug"));
        logger.setAdditive(false);
        return logger;
    }

    private static Appender<ILoggingEvent> createAppender(ch.qos.logback.classic.Logger logger) {
        RollingFileAppender appender = new RollingFileAppender();
        appender.setContext(loggerContext);
        appender.setName(logger.getName() + "Appender");
        appender.setAppend(true);

        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n");
        encoder.setContext(loggerContext);
        encoder.setParent(appender);
        appender.setEncoder(encoder);

        SizeAndTimeBasedRollingPolicy<ILoggingEvent> policy = new SizeAndTimeBasedRollingPolicy<>();
        policy.setMaxFileSize(FileSize.valueOf("5mb"));
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        String logDir = context.getProperty("LOG_DIR");
        if (logDir == null) {
            logDir = System.getProperty("LOG_DIR");
            if (logDir == null) {
                logDir = "logs";
            }
        }
        policy.setFileNamePattern(logDir + File.separator + logger.getName().toLowerCase() + ".%d{yyyy-MM-dd}.%i.log");
        policy.setParent(appender);
        policy.setContext(loggerContext);
        appender.setRollingPolicy(policy);

        policy.start();
        encoder.start();
        appender.start();
        return appender;
    }

}
